import {FormCascader} from '../components'
import gql from 'graphql-tag'
import {compose, withState} from 'recompose'
import {componentWillMount, withData} from '../hoc'
import {lensIndex, lensProp, over, set} from '../util'
import {withApollo} from 'react-apollo'

const categoryGql = gql`query AllCategories($filter:CategoryFilter){
    allCategories(filter:$filter){ id name family{id}}
}`

const familyGql = gql`query AllFamilies{
    allFamilies{ id name}
}`

const positionGql = gql`query AllPostions($filter:PositionFilter){
    allPositions(filter:$filter){ id name }
}`


const loadData = ({option, query, setState, initialValue, options, needPosition, state}) => {
    const filter = option ? option.length == 1 ? {familyId: option[0].value} : {categoryId: option[1].value} : {};

    const queryPosition = ({id, callback}) => {
        query({
            query: gql`query Position($id:ID!){Position(id:$id){ id name category{id name}}}`,
            variables: {id}
        }).then(({data: {Position}}) => {
            callback(Position)
        })
    }

    const queryCategory = ({id, callback}) => {
        query({
            query: gql`query Category($id:ID!){Category(id:$id){ id name family{id name}}}`,
            variables: {id}
        }).then(({data: {Category}}) => {
            callback(Category, id)
        })
    }
    const queryAllCategory = ({familyId, callback}) => {
        query({
            query: gql`query AllCategories($filter:CategoryFilter){allCategories(filter:$filter){ id name family{id name}}}`,
            variables: {filter: {familyId}}
        }).then(({data: {allCategories}}) => {
            callback(allCategories)
        })
    }
    return query({
        query: option ? option.length == 1 ? categoryGql : positionGql : familyGql,
        variables: {filter}
    }).then(({data}) => {
            if (!option) {
                if (initialValue) {
                    if (needPosition) {
                        queryPosition({
                            id: initialValue,
                            callback: position => queryCategory({
                                id: position.category.id,
                                callback: Category => {
                                    queryAllCategory({
                                        familyId: Category.family.id,
                                        callback: allCategories => {
                                            const families = data.allFamilies || [];
                                            let options = families.map((family, index) => ({
                                                index,
                                                value: family.id,
                                                isLeaf: false,
                                                label: family.name
                                            }));
                                            const familyIndex = options.findIndex(x => x.value == Category.family.id);
                                            const categoryIndex = allCategories.findIndex(x => x.id == Category.id);

                                            let categoryOptions = allCategories.map((category, i) => ({
                                                value: category.id,
                                                index: i,
                                                isLeaf: false,
                                                label: category.name,
                                            }))

                                            setState({
                                                initialValue: [families[familyIndex].id, Category.id, position.id],
                                                options: set(
                                                    lensIndex(familyIndex),
                                                    set(
                                                        lensProp('children'),
                                                        set(
                                                            lensIndex(categoryIndex),
                                                            set(
                                                                lensProp('children'),
                                                                [{
                                                                    index: 0,
                                                                    value: position.id,
                                                                    label: position.name
                                                                }],
                                                                categoryOptions[categoryIndex]
                                                            ),
                                                            categoryOptions
                                                        ),
                                                        options[familyIndex]
                                                    ),
                                                    options
                                                )
                                            });
                                        }
                                    })
                                }
                            })
                        })
                    } else {
                        queryCategory({
                            id: initialValue,
                            callback: Category => {
                                const families = data.allFamilies || [];
                                let options = families.map((family, index) => ({
                                    index,
                                    value: family.id,
                                    isLeaf: false,
                                    label: family.name
                                }));

                                const familyIndex = options.findIndex(x => x.value == Category.family.id);
                                setState({
                                    initialValue: [families[familyIndex].id, Category.id],
                                    options: set(
                                        lensIndex(familyIndex),
                                        set(
                                            lensProp('children'),
                                            [{
                                                index: 0,
                                                value: Category.id,
                                                label: Category.name,
                                            }],
                                            options[familyIndex]
                                        ),
                                        options
                                    )
                                });
                            }
                        })
                    }
                } else {
                    setState({
                        ...state,
                        options: data.allFamilies.map((family, index) => ({
                            index,
                            value: family.id,
                            label: family.name,
                            isLeaf: false
                        }))
                    });
                }
            } else if (option.length == 1) {
                const allCategories = (data.allCategories || []).map((category, index) => ({
                    value: category.id,
                    label: category.name,
                    isLeaf: needPosition ? false : true,
                    index
                }));
                setState({
                    ...state,
                    options: set(
                        lensIndex(option[0].index),
                        set(
                            lensProp('children'),
                            allCategories,
                            options[option[0].index]
                        ),
                        options
                    )
                })
            } else {
                const allPositions = (data.allPositions || []).map((position) => ({
                    value: position.id,
                    label: position.name,
                }));

                let family = options[option[0].index];
                let category = (family.children || [])[option[1].index];

                setState({
                    ...state,
                    options: set(
                        lensIndex(option[0].index),
                        set(
                            lensProp('children'),
                            set(
                                lensIndex(option[1].index),
                                set(lensProp('children'), allPositions, category),
                                family.children || []
                            ),
                            family
                        ),
                        options
                    )
                })
            }
        }
    )
}


const PositionSelect = props => {
    const {setState, needPosition, state, state: {options, initialValue}, client: {query}} = props;


    return (
        <FormCascader {...props}
                      initialValue={initialValue || []}
                      options={options}
                      loadData={option =>
                          needPosition
                              ? loadData({option, query, state, setState, options, needPosition})
                              : option.length < 2 && loadData({option, query, setState, options, needPosition})
                      }
        />
    )
}


export default compose(
    withState('state', 'setState', {
        options: [],
        initialValue: null,
    }),
    withData,
    withApollo,
    componentWillMount([
        ({setState, state, needPosition, initialValue, client: {query}}) => loadData({
            state,
            option: null,
            needPosition,
            query,
            setState,
            initialValue
        })
    ])
)
(PositionSelect)